package com.example.blog.config;

import com.example.blog.aop.CustomizationAop;
import com.example.blog.controller.BaseController;
import com.example.blog.domain.OperationalLogs;
import com.example.blog.domain.Response;
import com.example.blog.exception.BusinessException;
import com.example.blog.exception.SystemException;

import com.example.blog.service.impl.OperationalLogsServiceImpl;
import com.example.blog.utils.IpUtil;
import com.example.blog.utils.JwtUtils;
import com.example.blog.utils.MyMail;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.ip2region.core.IpInfo;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.Objects;

import static com.example.blog.domain.Response.ERROR_PARAMETER;
import static com.example.blog.domain.Response.ERROR_Permissions;


//异常处理器 ，系统中所有的异常都会被集中在这处理
@RestControllerAdvice
@Slf4j
public class ProjectExceptionAdvice extends BaseController {
    private final MyMail myMail;
    OperationalLogsServiceImpl operationalLogsService;
    private final Ip2regionSearcher ip2regionSearcher;
    private final StringBuffer stringBuffer = new StringBuffer();
    @Value("${emailConfig.exception}")
    private String TO;

    @Autowired
    public ProjectExceptionAdvice(Ip2regionSearcher ip2regionSearcher, MyMail myMail, OperationalLogsServiceImpl operationalLogsService) {
        this.ip2regionSearcher = ip2regionSearcher;
        this.myMail = myMail;
        this.operationalLogsService = operationalLogsService;
    }

    //第三方异常 即找不到问题时
    @ExceptionHandler(Exception.class)
    public Response doException(@NotNull Exception ex) {
        HttpServletRequest request = getHttpInfo();
        String ip = IpUtil.getIpAddress(request);
        IpInfo ipInfo = ip2regionSearcher.memorySearch(ip);
        try {
            myMail.sendSimpleMail("系统未知异常", TO,
                    stringBuffer
                            .append("<ul style='color:red'>")
                            .append(ex.getMessage())
                            .append("<br>")
                            .append(ex.getCause())
                            .append("</ul>").toString(),
                    true);
        } catch (MessagingException e) {
            log.warn("发送邮件异常！{}", e);
        }
        Claims claims = JwtUtils.checkToken(request.getHeader("token"));
        log.error("请求路径：{} 用户名/用户ID：{}  访问IP：{}  {} {}",
                request.getRequestURL().toString(),
                claims != null ? String.valueOf(claims.get("uid")) : "游客",
                ip,
                ipInfo != null ? ipInfo.getAddress() : "未知", ex);
        return new Response(Response.SYSTEM_ERROR_EXCEPTION, "系统繁忙，请稍后再试！", null);
    }

    @ExceptionHandler(SystemException.class)
    public Response doSystemException(SystemException ex) {
        HttpServletRequest request = getHttpInfo();
        String ip = IpUtil.getIpAddress(request);
        IpInfo ipInfo = ip2regionSearcher.memorySearch(ip);
        try {
            myMail.sendSimpleMail("系统运行异常", TO,
                    stringBuffer
                            .append("<ul style='color:red'> ")
                            .append(ex.getCode())
                            .append("</br>")
                            .append(ex.getMessage())
                            .append("</br>")
                            .append(ex.getCause())
                            .append("</ul>").toString(),
                    true);
        } catch (MessagingException e) {
            log.warn("发送邮件异常！{}", e);
        }
        Claims claims = JwtUtils.checkToken(request.getHeader("token"));
        log.error("请求路径：{} 用户名/用户ID：{}  访问IP：{}  {} {}",
                request.getRequestURL().toString(),
                claims != null ? String.valueOf(claims.get("uid")) : "游客",
                ip,
                ipInfo != null ? ipInfo.getAddress() : "未知", ex);
        return new Response(ex.getCode(), "系统异常", null);
    }

    //业务出现的异常后者错误
    @ExceptionHandler(value = {BusinessException.class, NullPointerException.class ,ConstraintViolationException.class, MethodArgumentTypeMismatchException.class})
    public Response doBusinessException(@NotNull Exception ex) {
        String msg = "未知ip";
        if (ex instanceof ConstraintViolationException) {
            ConstraintViolationException e = (ConstraintViolationException) ex;
            return new Response(ERROR_PARAMETER, StringUtils.substringAfter(e.getMessage(), ":").trim());
        } else if (ex instanceof MethodArgumentTypeMismatchException) {
            MethodArgumentTypeMismatchException e = (MethodArgumentTypeMismatchException) ex;
            return new Response(ERROR_PARAMETER, e.getMessage());
        } else if(ex instanceof NullPointerException){
            return new Response(ERROR_PARAMETER, ex.getMessage());
        }
        BusinessException e = (BusinessException) ex;
//        if (Objects.equals(e.getCode(), ERROR_Permissions)) {
//            return new Response(ERROR_Permissions, e.getMessage(),null);
//        }
        try {
            HttpServletRequest request = getHttpInfo();
            String ip = IpUtil.getIpAddress(request);
            IpInfo ipInfo = ip2regionSearcher.memorySearch(ip);
            operationalLogsService.save(new OperationalLogs(1, 0, e.getMessage(),
                    getLogSign().getUsername(), "失败", ip, ipInfo == null ? "未知" : ipInfo.getAddress()));
            Claims claims = JwtUtils.checkToken(request.getHeader("token"));
            log.error("{} 请求路径：{} 用户名/用户ID：{}  访问IP：{}  {} {}",
                    e.getMessage(),
                    request.getRequestURL().toString(),
                    claims != null ? String.valueOf(claims.get("uid")) : "游客",
                    ip,
                    ipInfo != null ? ipInfo.getAddress() : msg,
                    ((BusinessException) ex).getException());
        } catch (Exception logEx) {
            log.error("记录错误日志失败", logEx);
        }
        return new Response(e.getCode(), Objects.equals(ex.getMessage(), null) ? "操作失败!" : ex.getMessage(), null);
    }

}
